﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConferenceArranger.ConferenceComponent;

namespace ConferenceArranger.Strategy
{   
    /// <summary>
    /// Given a list of talks, select the talks so that 
    /// the sum of intervals can be maximized within session interval 
    /// (either 180 mins or 240mins)
    /// </summary>
    class SessionScheduler
    {   
        // input
        int sessionLength;
        List<Talk> givenTalks;

        //output
        List<Talk> chosenTalks;
        List<Talk> returnedTalks;

        //maximum time utilized 
        int[,] maxValue;
        // indicated if the talk should be chosen
        bool[,] used;
        

        public SessionScheduler(int sessionLength, List<Talk> givenTalks)
        {
            this.givenTalks = givenTalks;
            this.chosenTalks = new List<Talk>();
            this.returnedTalks = new List<Talk>();
            this.sessionLength = sessionLength;
            InitValueArray();
        }

        /// <summary>
        /// main method of this class
        /// include 3 component tasks inside
        /// </summary>
        public void SelectTalk()
        {
            CalculateValueArray();
            SetChosenTalks();
            SetReturnedTalks();
        }

        /// <summary>
        /// prepartion before calculating
        /// </summary>
        public void InitValueArray()
        {
            maxValue = new int[sessionLength + 1, givenTalks.Count];
            used = new bool[sessionLength + 1, givenTalks.Count];

            for (int va = 0; va <= sessionLength; va++)
            {
                maxValue[va, 0] = 0;
            }

            for (int o = 0; o < givenTalks.Count; o++)
            {
                maxValue[0, o] = 0;
            }
        }

        /// <summary>
        /// similar to knapsack problem,maximize the time utilized within the session interval
        /// </summary>
        public void CalculateValueArray()
        {
            for (int s = 1; s <= sessionLength; s++)
            {
                for (int o = 1; o < givenTalks.Count; o++)
                {
                    if (givenTalks[o].GetInterval() <= s)
                    {
                        maxValue[s, o] = Math.Max(maxValue[s, o - 1],
                                        maxValue[s - givenTalks[o].GetInterval(), o - 1] + givenTalks[o].GetInterval());

                        if (maxValue[s, o] == maxValue[s, o - 1])
                        {
                            used[s, o] = false;
                        }
                        else used[s, o] = true;
                    }
                    else
                    {
                        maxValue[s, o] = maxValue[s, o - 1];
                        used[s, o] = false;
                    }
                }
            }
        }

        /// <summary>
        /// after calculate the best method, backtrack to find the selected talks
        /// </summary>
        public void SetChosenTalks()
        {
            int left = maxValue[sessionLength, givenTalks.Count - 1];
            for (int i = givenTalks.Count - 1; i > 0; i--)
            {
                if (used[left, i] == true)
                {
                    chosenTalks.Add(givenTalks[i]);
                    left = left - givenTalks[i].GetInterval();
                }
            }
        }

        /// <summary>
        /// find the talks not used, these talks will be considered for other sessions
        /// </summary>
        public void SetReturnedTalks()
        {
            foreach (Talk t in chosenTalks)
            {
                givenTalks.Remove(t);
            }
            returnedTalks = givenTalks;
        }

        public List<Talk> GetReturnedTalks()
        {
            return returnedTalks;
        }

        public List<Talk> GetChosenTalks()
        {
            return chosenTalks;
        }
        /* for testing
        public string ToString()
        {
            string myString = "";
            for (int i = 0; i < chosenTalks.Count; i++)
            {
                myString += givenTalks[i].GetTitle() + givenTalks[i].GetInterval() + "\r\n";
            }
            return myString;
        }
        */
    }
}
